/*
* Licensed under the MIT License
* 
* Copyright (c) 2010 Kay Kreuning
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* 
* http://code.google.com/p/as3hyvesapi
*/
package nl.hyvesstudio.oauth {
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.net.URLRequest;
	
	import nl.hyvesstudio.oauth.authorization.IAuthorizer;
	import nl.hyvesstudio.oauth.signing.ISignatureMethod;
	import nl.hyvesstudio.oauth.signing.SignatureMethod_HMAC_SHA1;
	import nl.hyvesstudio.utils.ObjectUtil;
	import nl.hyvesstudio.utils.URLUtil;
	
	/**
	 * Dispatched when an accesstoken is available eg. the service is authorized.
	 * 
	 * @eventType flash.events.Event.COMPLETE
	 */
	[Event(name="complete", type="flash.events.Event")]
	
	/**
	 * This class is an abstraction layer between your code and an OAuth provider,
	 * it handles authorization and generation of OAuth compatible <code>URLRequest</code>s.
	 * 
	 * @author Kay Kreuning
	 */
	public class OAuthService extends EventDispatcher implements IOAuthService {
		
		private var _accesstoken:Accesstoken;
		private var _signatureMethod:ISignatureMethod;
		private var _isAuthorized:Boolean;
		private var _httpMethod:String;
		
		private var consumerKey:String;
		private var consumerSecret:String;
		private var platformParameters:Object;
		
		/** @inheritDoc */
		public function get accesstoken():Accesstoken {
			return _accesstoken;
		}
		
		/** @private */
		public function set accesstoken(value:Accesstoken):void {
			_accesstoken = value;
			
			if (accesstoken && accesstoken.userId && accesstoken.methods && accesstoken.expireDate) {
				_isAuthorized = true;
				
				dispatchEvent(new Event(Event.COMPLETE));
			}
		}
		
		/** @inheritDoc */
		public function get signatureMethod():ISignatureMethod
		{
			if (!_signatureMethod)
				_signatureMethod = new SignatureMethod_HMAC_SHA1();
			
			return _signatureMethod;
		}
		
		/** @private */
		public function set signatureMethod(value:ISignatureMethod):void
		{
			_signatureMethod = value;
		}
		
		/** @inheritDoc */
		public function get httpMethod():String
		{
			if (!_httpMethod)
				httpMethod = "GET";
			
			return _httpMethod;			
		}
		
		/** @private */
		public function set httpMethod(value:String):void
		{
			_httpMethod = value;
		}
		
		/** @inheritDoc */
		public function get isAuthorized():Boolean {
			return _isAuthorized;
		}
		
		/**
		 * Construct a new OAuthService instance.
		 * 
		 * @param consumerKey OAuth consumer key
		 * @param consumerSecret OAuth consumer secret
		 * @param signatureMethod <code>ISignatureMethod</code> instance used to sign requests
		 * @param platformParameters parameters that will be included in every generated request
		 */
		public function OAuthService(consumerKey:String, consumerSecret:String, platformParameters:Object = null) {
			this.consumerKey = consumerKey;
			this.consumerSecret = consumerSecret;
			
			this.platformParameters = platformParameters;
		}
		
		/** @inheritDoc */
		public function createURLRequest(url:String, parameters:Object):URLRequest {
			
			if (!signatureMethod)
				throw new Error("Cannot create URLRequest without a signature method, specify one first.");
			
			parameters = ObjectUtil.merge(parameters, platformParameters);
			
			if (accesstoken)
				parameters["oauth_token"] = accesstoken.token;
			
			parameters["oauth_nonce"] = int(Math.random() * 0x7FFFFFFF).toString();
			parameters["oauth_timestamp"] = int(new Date().getTime() * .001 + .5).toString();
			parameters["oauth_consumer_key"] = consumerKey;
			parameters["oauth_signature_method"] = signatureMethod.methodName;
			parameters["oauth_signature"] = signatureMethod.calculateSignature(
				parameters,
				url,
				consumerSecret,
				accesstoken ? accesstoken.secret : "",
				httpMethod);
			
			return new URLRequest(url + "?" + URLUtil.decodeToGetVariables(parameters));
		}
		
		/** @inheritDoc */
		public function authorize(authorizer:IAuthorizer):void
		{
			authorizer.authorize(this);
		}
	}
}